﻿using System;
using System.ComponentModel;

namespace Simp.CodeModel
{
	/// <summary>Holds a call to a function.</summary>
	[ImmutableObjectAttribute(true)]
	public abstract class FunctionCallingBase : ParameterLessFunctionBase
	{
		private readonly IFunctionParameterBinding[] _parameters;

		/// <summary>Constructor taking the function's parameter values.</summary>
		/// <param name="parameters"></param>
		public FunctionCallingBase(IFunctionParameterBinding[] parameters)
		{
			if (parameters == null)
			{
				throw new ArgumentNullException("parameters");
			}
			_parameters = parameters;
		}

		/// <summary>Parameters to apply on the function.</summary>
		public IFunctionParameterBinding[] FunctionParameters
		{
			get { return _parameters; }
		}

		/// <summary>Accepts the visitor and let it visit each parameters.</summary>
		/// <param name="visitor"></param>
		/// <returns></returns>
		public override IFunction AcceptVisitor(IFunctionVisitor visitor)
		{
			bool hasChanged = false;
			IFunctionParameterBinding[] newBindings = new IFunctionParameterBinding[FunctionParameters.Length];

			for (int i = 0; i != newBindings.Length; ++i)
			{
				var param = FunctionParameters[i];
				var newValue = visitor.Visit(param.Value);

				if (newValue != null)
				{
					newBindings[i] = FunctionHelper.FunctionParameterBindingFactory.Build(param.Name, newValue);
					hasChanged = true;
				}
				else
				{
					newBindings[i] = param;
				}
			}

			if (hasChanged)
			{
				return CreateNewVersion(newBindings);
			}
			else
			{	//	Nothing has changed
				return null;
			}
		}

		/// <summary>Creates a new version of itself with new bindings.</summary>
		/// <remarks>Used by <see cref="AcceptVisitor"/>.</remarks>
		/// <param name="newBindings"></param>
		/// <returns></returns>
		protected abstract IFunction CreateNewVersion(IFunctionParameterBinding[] newBindings);
	}
}